/*
 ============================================================================
 Name        :	w_parser.c
 Author      :	NAYED (nizar.ayed@fullcommedia.com)
 Version     :	0.1
 Copyright   :	Code delivered as is with no liability. No commercial use
 is allowed without written authorization from the Author. 
 Description :	Cf. "w_parser.h"
 -+ comment_line ::= <#> {p_car} <EOL>
 -+ comment_multiln ::= </> <*> {p_car | <EOL>} <*> </>
 -+ code ::= instruction { space instruction }
 -+ space ::= <space> | <EOL>
 -+ instruction ::= proc | func | int | float | string | identifier | equal 
 -+ proc ::= <[> {params} <|> {code} <]>
 -+ func ::= <{> {params} <|> {code} <}>
 -+ params ::= identifier {<,> identifier} [<,> <...>]
 -+ float ::= int <.> digit {digit} [exposant]
 -+ int ::= {sign} digit {digit}
 -+ digit  ::= <0> | <1> | <2> | .. | <9>
 -+ exposant ::= (<e> | <E>) int
 -+ sign ::= <+> | <->
 -+ string ::= <"> {p_car | esc_car | hex_car} <">
 -+ p_car ::= { <any printable car> }
 -+ esc_car ::= <">|<?>|<\>|<a>|<b>|<f>|<n>|<r>|<t>|<v>
 -+ hex_car ::= <\> (<x>|<X>) hex_digit hex_digit
 -+ hex_digit ::= (digit|<a>|<b>| .. |<f>|<A>|<B>| .. |<F>)
 -+ identifier ::= alpha {alpha | digit}
 -+ alpha ::= letter | symbol
 -+ letter  ::= <a> | <b> | <c> | .. | <z> | <A> | <B> | <C> | .. | <Z>
 -+ symbol ::= <_> | <$>
 -+ equal ::= <=>
 ============================================================================
 */

#include "w_parser.h"

char read_char(char *buffer) {
	return *buffer;
}

char* read_word(FILE *file) {
	result_buffer = malloc(sizeof(char) * MAX_TOKEN_SIZE);
	int len = 0;
	char c;
	while ((c = fgetc(file)) != ' ') {
		result_buffer[len] = c;
		result_buffer[++len] = '\0';
	}
	return result_buffer;
}

bool is_symbol(char c) {
	return ( c == '_' || c == '$' );
}

bool is_digit(char c) {
	return ( c >= '0' && c <= '9' );
}

bool is_letter(char c) {
	return (( c >= 'a' && c <= 'z' ) ||
			( c >= 'A' && c <= 'Z' )  );
}

bool is_alpha(char c) {
	return ( is_letter(c) || is_symbol(c) );
}

bool is_sign(char c) {
	return ( c == '+' || c == '-' );
}

bool is_p_car(char c) {
	return ( ( c >= ' ' && c <= '~' ) );
}

bool is_esc_car(char* word) {
	bool flag = (word[0] ? (word[0] == '\\') : false);
	word++;
	
	flag &= (word[0] == '"' || word[0] == '?' ||
					word[0] == '\\' || word[0] == 'a' ||
					word[0] == 'b' || word[0] == 'f' ||
					word[0] == 'n' || word[0] == 'r'  ||
					word[0] == 't' || word[0] == 'v'   );
	return flag;
}

bool is_space(char c) {
	return (c == ' ' || c == '\n');
}

bool is_identifier(char *word) {
	// identifier ::= alpha {alpha | digit}

	bool flag = is_alpha(word[0]);
	word++;
	
	while (flag && word[0]) {
		flag = flag && (is_alpha(word[0]) || is_digit(word[0]));
		word++;
	}
	return flag;
}

bool is_int(char *word) {
	// int ::= {sign} digit {digit}
	while (is_sign(word[0])) {
		word++;
	}
	
	bool flag = is_digit(word[0]);
	word++;
	
	while (flag && word[0]) {
		flag = flag && is_digit(word[0]);
		word++;
	}
	
	return flag;
}

bool is_float(char *word) {
	// float ::= int <.> digit {digit} [exposant]
	// A OPTIMISER SI POSSIBLE!
	char* dot_ptr = index(word, '.');
	if (!dot_ptr) {
		return false;
	}
	
	char* cursor = word;
	char* int_part = malloc(sizeof(char) * (dot_ptr - word + 1));
	for (; word < dot_ptr; word++) {
		int_part[word - cursor] = word[0];
	}
	int_part[word - cursor] = '\0';
	word++;
	
	bool flag = is_int(int_part) && is_digit(word[0]);
	word ++;
	
	while (word[0] && is_digit(word[0])) {
		word++;
	}

	return flag && (word[0] ? is_exposant(word) : true);
}

bool is_exposant(char *word) {
	// exposant ::= (<e> | <E>) int
	bool flag = (word[0] == 'e') || (word[0] == 'E');
	word++;
	
	return flag && is_int(word);
}

bool is_string(char *word) {
	// string ::= <"> {p_car | esc_car | hex_car} <">
	bool flag = (word[0] ? (word[0] == '\"') : false);
	word++;
	
	while (word[0]) {
		if(word[0] == '\"') {
			break;
		} else if (!is_esc_car(word) && 
				   !is_p_car(word[0]) &&
				   !is_hex_car(word)) {
			flag &= false;
			break;
		} else {
			word++;
		}

	}
	
	flag &= (word[0] ? word[0] == '\"' : false);
	return flag;
}

bool is_hex_car(char *word) {
	// hex_car ::= <\> (<x>|<X>) hex_digit hex_digit
	bool flag = (word[0] ? word[0] == '\\' : false);
	word++;
	flag &= (word[0] ? (word[0] == 'x' || word[0] == 'X') : false);
	word++;
	flag &= (word[0] ? is_hex_digit(word[0]) : false);
	word++;
	flag &= (word[0] ? is_hex_digit(word[0]) : false);
	
	return flag;
}

bool is_hex_digit(char c) {
	// hex_digit ::= (digit|<a>|<b>| .. |<f>|<A>|<B>| .. |<F>)
	return (is_digit(c) ||
			( c >= 'a' && c <= 'f' ) ||
			( c >= 'A' && c <= 'F' )  );
}

bool is_proc(char *word) {
	/* TO DO: Add code here */
	return false;
}

bool is_func(char *word) {
	/* TO DO: Add code here */
	return false;
}

bool is_params(char *word) {
	/* TO DO: Add code here */
	return false;
}

bool is_code(char *word) {
	/* TO DO: Add code here */
	return false;
}

bool is_instruction(char *word) {
	/* TO DO: Add code here */
	return false;
}

bool is_equal(char *word) {
	/* TO DO: Add code here */
	return false;
}

bool is_comment_line(char *word) {
	/* TO DO: Add code here */
	return false;
}

bool is_comment_multiln(char *word) {
	/* TO DO: Add code here */
	return false;
}